/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.qb9.flashlib.net
{
	import com.qb9.flashlib.tasks.Task;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;

	/** Task for loading one file (any format). */
	public class LoadFile extends Task
	{
		protected static const EVENTS:Array = [ProgressEvent.PROGRESS,Event.COMPLETE];
		
		/** URL of the loaded file. */
		public var url:String;
		/** Identifier of the loader. By default it will be equal to the url. */
		public var id:String;
		
		protected var loader:ILoader;
		protected var silent:Boolean;
		protected var failed:Boolean = false;
		
		/**
		 * Create a LoadFile instance.
		 *
		 * @param url URL of the filr to be loaded.
		 * @param format Format of the file to be loaded.
		 * @param id Unique identifier for the loader. By default it will be equal to the url.
		 * @param silent If true, when a file fails to load, it will fail silently and the 'data' will be null
		 */
		public function LoadFile(url:String, format:String = LoadFileFormat.INFER, id:String = null, silent:Boolean=false)
		{
			this.url = url;
			this.id = id || url;
			this.loader = LoadFile.makeLoader(format, url);
			this.silent = silent;
		}

		/** @inheritDoc */
		public override function start():void
		{
			super.start();
			
			for each(var event:String in EVENTS)
				loader.addEventListener(event, dispatchEvent);

			loader.addEventListener(Event.COMPLETE, onComplete);
			loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
			loader.loadURL(new URLRequest(url));
		}

		/** @inheritDoc */
		public override function stop():void
		{
			super.stop();

			for each(var event:String in EVENTS)
				loader.removeEventListener(event, dispatchEvent);

			loader.removeEventListener(Event.COMPLETE, onComplete);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
		}

		private function errorHandler(e:Event):void
		{
			failed = true;
			if (silent)
				this.taskComplete();
			else
				throw new Error(Object(e).text);
		}

		protected function onComplete(e:Event):void
		{
			taskComplete();
		}

		public function get dataFormat():String
		{
			return loader.getDataFormat();
		}
		
		public function get loading():Boolean
		{
			return !failed && running && bytesTotal !== 0;
		}
		
		public function get loaded():Boolean
		{
			return failed || bytesTotal !== 0 && bytesLoaded === bytesTotal;
		}
		
		/** Get the loaded data. */
		public function get data():*
		{
			return failed ? null : loader.getData();
		}
		
		public function get bytesLoaded():uint
		{
			return loader.getBytesLoaded();
		}
		
		public function get bytesTotal():uint
		{
			return loader.getBytesTotal();
		}
		
		/** Utility loader function, useful for simple situations. */
		public static function load(url:String, complete:Function, format:String = LoadFileFormat.INFER):ILoader
		{
			var loader:ILoader = makeLoader(format, url);
			
			loader.addEventListener(Event.COMPLETE, function(e:Event) : void {
				complete(loader.getData());
				// Cleanup
				loader.removeEventListener(Event.COMPLETE, arguments.callee);
			});
				
			loader.loadURL(new URLRequest(url));
			return loader;
		}
		
		/** Utility function to create an ILoader instance based on the file format. */
		public static function makeLoader(format:String, url:String = null) : ILoader
		{
			if (!format || format == LoadFileFormat.INFER)
				format = LoadFileFormat.infer(url);
				
			var loader:ILoader;
			switch (format)
			{
				case LoadFileFormat.SOUND:
					loader = new QSound();
				break;	
				case LoadFileFormat.SWF:
				case LoadFileFormat.IMAGE:
					loader = new QLoader();
				break;	
				case LoadFileFormat.JSON:
				case LoadFileFormat.XML:
				case LoadFileFormat.PLAIN_TEXT:
				case LoadFileFormat.BINARY:
				case LoadFileFormat.VARIABLES:
					loader = new QURLLoader();
				break;
				default:
					throw new ArgumentError('LoadFile > Unknown file format:' + format);
            }
            loader.setDataFormat(format);
            return loader;
		}		
	}
}
